#include <string.h>
#include <cmath>
#include <iostream>  //预处理器指令 a PREPROCESSOR directive
using namespace std; // 使定义可见   make definitions visible
#include <vector>
#include <array>
#include <new>


/*
  13.3 银行客户案例 - 使用抽象类

  虚方法(virtual method)

  抽象基类(abstract base class,ABC)

  纯虚函数(pure virtual function)提供未实现的函数。纯虚函数声明的结尾处为=0

  //当类声明中包含纯虚函数时，则不能创建该类的对象。
  //ABC描述的是至少使用一个纯虚函数的接口

*/

// Abstract Base Class
class AcctABC
{
private:
    std::string fullName; //姓名
    long acctNum; //账号
    double balance; //余额
protected:
    struct Formatting
    {
      std::ios_base::fmtflags flag;
      std::streamsize pr;
    };
    //获取姓名
    const std::string & FullName() const {return fullName;}
    //获取账号
    long AcctNum() const {return acctNum;}

    Formatting SetFormat() const;
    void Restore(Formatting & f) const;

//当类声明中包含纯虚函数时，则不能创建该类的对象。
//ABC描述的是至少使用一个纯虚函数的接口
public: 
    AcctABC(const std::string & s = "Nullbody", long an = -1,
                double bal = 0.0);

    //创建账户
    void Deposit(double amt) ; 

    //取款
    virtual void Withdraw(double amt) = 0; // pure virtual function

    //得到余额
    double Balance() const {return balance;}; 
    
    //显示账户信息
    virtual void ViewAcct() const = 0;     // pure virtual function

    virtual ~AcctABC() {}
};


// 银行客户类
// Brass Account Class
class Brass :public AcctABC
{
public:
    Brass(const std::string & s = "Nullbody", long an = -1,
           double bal = 0.0) : AcctABC(s, an, bal) { }

    virtual void Withdraw(double amt);

    virtual void ViewAcct() const;

    virtual ~Brass() {}
};

// 银行客户plus类
//Brass Plus Account Class
class BrassPlus : public AcctABC
{
private:
    double maxLoan; //透支上限
    double rate; //透支贷款利率
    double owesBank; //当前的透支总额
public:
    BrassPlus(const std::string & s = "Nullbody", long an = -1,
            double bal = 0.0, double ml = 500,
            double r = 0.10);
    BrassPlus(const Brass & ba, double ml = 500, double r = 0.1);
    virtual void ViewAcct()const;
    virtual void Withdraw(double amt);

    void ResetMax(double m) { maxLoan = m; }
    void ResetRate(double r) { rate = r; };
    void ResetOwes() { owesBank = 0; }
};







int mian{


};
















// Abstract Base Class
AcctABC::AcctABC(const string & s, long an, double bal)
{
    fullName = s;
    acctNum = an;
    balance = bal;
}

void AcctABC::Deposit(double amt)
{
    if (amt < 0)
        cout << "Negative deposit not allowed; "
             << "deposit is cancelled.\n";
    else
        balance += amt;
}

void AcctABC::Withdraw(double amt)
{
    balance -= amt;
}

// protected methods for formatting
AcctABC::Formatting AcctABC::SetFormat() const
{
 // set up ###.## format
    Formatting f;
    f.flag = cout.setf(ios_base::fixed, ios_base::floatfield);
    f.pr = cout.precision(2);
    return f; 
}

void AcctABC::Restore(Formatting & f) const
{
    cout.setf(f.flag, ios_base::floatfield);
    cout.precision(f.pr);
}

// Brass methods
void Brass::Withdraw(double amt)
{
    if (amt < 0)
        cout << "Withdrawal amount must be positive; "
             << "withdrawal canceled.\n";
    else if (amt <= Balance())
        AcctABC::Withdraw(amt);
    else
        cout << "Withdrawal amount of $" << amt
             << " exceeds your balance.\n"
             << "Withdrawal canceled.\n";
}

void Brass::ViewAcct() const
{
   
    Formatting f = SetFormat();
    cout << "Brass Client: " << FullName() << endl;
    cout << "Account Number: " << AcctNum() << endl;
    cout << "Balance: $" << Balance() << endl;
    Restore(f);
}

// BrassPlus Methods
BrassPlus::BrassPlus(const string & s, long an, double bal,
           double ml, double r) : AcctABC(s, an, bal)
{
    maxLoan = ml;
    owesBank = 0.0;
    rate = r; 
}

BrassPlus::BrassPlus(const Brass & ba, double ml, double r)
           : AcctABC(ba)   // uses implicit copy constructor
{
    maxLoan = ml;
    owesBank = 0.0;
    rate = r;
}

void BrassPlus::ViewAcct() const
{
    Formatting f = SetFormat();

    cout << "BrassPlus Client: " << FullName() << endl;
    cout << "Account Number: " << AcctNum() << endl;
    cout << "Balance: $" << Balance() << endl;
    cout << "Maximum loan: $" << maxLoan << endl;
    cout << "Owed to bank: $" << owesBank << endl;
    cout.precision(3);
    cout << "Loan Rate: " << 100 * rate << "%\n";
    Restore(f);
}

void BrassPlus::Withdraw(double amt)
{
    Formatting f = SetFormat();

    double bal = Balance();
    if (amt <= bal)
        AcctABC::Withdraw(amt);
    else if ( amt <= bal + maxLoan - owesBank)
    {
        double advance = amt - bal;
        owesBank += advance * (1.0 + rate);
        cout << "Bank advance: $" << advance << endl;
        cout << "Finance charge: $" << advance * rate << endl;
        Deposit(advance);
        AcctABC::Withdraw(amt);
    }
    else
        cout << "Credit limit exceeded. Transaction cancelled.\n";
    Restore(f); 
}
